from abc import ABCMeta, abstractmethod
from sqlalchemy.orm import Session
from docker import DockerClient
from app.controller.model.storage import GetStorageListRes, GetStorageListItem
from app.dao.storage import get_storage, get_storage_count
from app.docker import Client


class StorageLister(metaclass=ABCMeta):
    @abstractmethod
    def list(self) -> GetStorageListRes:
        pass


class StorageListerImpl(StorageLister):
    db: Session
    page: int
    size: int
    client: DockerClient

    def __init__(self, db: Session, *, page: int, size: int, client: DockerClient) -> None:
        super().__init__()
        self.db = db
        self.page = page
        self.size = size
        self.client = client

    def _get_service_form_db(self):
        return get_storage(self.db, page=self.page, size=self.size)

    def _get_service_num_form_db(self):
        return get_storage_count(self.db)

    def _get_node_addr(self, main_node_id):
        ins = self.client.api.inspect_node(main_node_id)
        return ins['Status']['Addr']

    def _get_size_for_HDFS(self, servicename):
        count = 0
        services = self.client.services.list()
        length = len(servicename)
        for service in services:
            if service.name != servicename and service.name[0:length] == servicename:
                count += 1
        return count

    def _get_detail_by_service_id(self, id):
        services = self.client.services.list(filters={'id': id})
        if len(services) == 0:
            return None
        service = services[0]
        tasks = service.tasks()

        main_node_addr = ''
        time = ''
        tarsize = 0
        for task in tasks:
            if task['Status']['State'] == 'running':
                main_node_id = task['NodeID']
                main_node_addr = self._get_node_addr(main_node_id)
                time = task['CreatedAt']
                break
        if service.name[0:4] == "HDFS":
            tarsize = self._get_size_for_HDFS(service.name)
        else:
            for task in tasks:
                if task['Status']['State'] == 'running':
                    tarsize += 1
        time = time.split('.')[0]
        time = ' '.join(time.split('T'))

        return GetStorageListItem(
            id=id,
            mainNode=main_node_addr,
            size=tarsize,
            mainMemory=0,
            slaveMemory=0,
            type=0,
            time=time
        )

    def list(self) -> GetStorageListRes:
        storgaes = self._get_service_form_db()
        count = self._get_service_num_form_db()

        items = []
        for storage in storgaes:
            tmp = self._get_detail_by_service_id(storage.service_id)
            if tmp is None:
                continue

            tmp.mainMemory = storage.main_memory
            tmp.slaveMemory = storage.slave_memory
            tmp.type = storage.type

            items.append(tmp)

        return GetStorageListRes(total=count, item=items)


def get_storage_lister(db: Session, *, page: int, size: int) -> StorageLister:
    return StorageListerImpl(db, page=page, size=size, client=Client().client)
